package com.assignwork.service.impl;

import com.assignwork.dto.*;
import com.assignwork.entity.DailyShift;
import com.assignwork.entity.ShiftRule;
import com.assignwork.mapper.ShiftRuleMapper;
import com.assignwork.service.IDailyShiftService;
import com.assignwork.service.IShiftRuleDailyShiftService;
import com.assignwork.service.IShiftRuleService;
import com.assignwork.service.IShiftRuleTimeSpaceService;
import com.assignwork.vo.DailyShiftVO;
import com.assignwork.vo.ShiftRuleTimeSpaceVO;
import com.assignwork.vo.ShiftRuleVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.AllArgsConstructor;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.tool.utils.Func;
import org.springblade.system.cache.DictBizCache;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @ClassName ShiftRuleServiceImpl
 * @Description 班组生成规则接口实现
 * @Author dujianyu
 * @Date 2023/12/1 15:44
 */
@Service
@AllArgsConstructor
public class ShiftRuleServiceImpl extends BaseServiceImpl<ShiftRuleMapper, ShiftRule> implements IShiftRuleService {

    private IShiftRuleDailyShiftService srDailyShiftService;
    private IShiftRuleTimeSpaceService srTimeSpaceService;
    private IDailyShiftService shiftService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean submitShiftRule(ShiftRuleSubmitDTO dto) {
        boolean success = false;
        try {
            if (!Func.isNull(dto.getId())) {
                success = srTimeSpaceService.removeSRTimeSpacesByRuId(dto.getId()) && srDailyShiftService.removeSRDailyShiftsByRuId(dto.getId());
            }
            int ruleTimes = 0;
            int ruleShifts = 0;
            if (!Func.isEmpty(dto.getDailyShifts())) {
                ruleShifts = dto.getDailyShifts().size();
            }
            if (!Func.isEmpty(dto.getTimeSpaces())) {
                ruleTimes = dto.getTimeSpaces().size();
            }
            ShiftRule entity = new ShiftRule();
            entity.setId(dto.getId());
            entity.setShifts(ruleShifts);
            entity.setTimes(ruleTimes);
            entity.setName(dto.getName());
            entity.setStatus(dto.getStatus());
            if (super.saveOrUpdate(entity)) {
                List<ShiftRuleTimeSpaceSubmitDTO> timeSpaces = dto.getTimeSpaces().stream().peek(i -> i.setRuleId(entity.getId())).collect(Collectors.toList());
                List<ShiftRuleDailyShiftSubmitDTO> dailyShifts = dto.getDailyShifts().stream().peek(i -> i.setRuleId(entity.getId())).collect(Collectors.toList());
                success =  srTimeSpaceService.submitSRTimeSpaceBatch(timeSpaces) && srDailyShiftService.submitSRDailyShiftBatch(dailyShifts);
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        } 
        return success;
    }

    @Override
    public List<DailyShiftVO> getExample(ShiftRuleSubmitDTO dto) {
        Map<Integer, String> shiftCode = dto.getDailyShifts().stream().collect(Collectors.toMap(ShiftRuleDailyShiftSubmitDTO::getCode, ShiftRuleDailyShiftSubmitDTO::getDailyShift, (key1 , key2) -> key1));

//        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        LocalDate startDate = LocalDate.of(LocalDate.now().getYear(),1,1);
        LocalDate endDate = startDate.plusDays(31);
        int loopTime = Func.toInt(startDate.until(endDate, ChronoUnit.DAYS));

        LocalDate theDay = startDate;
        List<DailyShiftVO> res = new ArrayList<>();
        for (int i = 0; i < loopTime; i++) {
            for (ShiftRuleTimeSpaceSubmitDTO timeSpace : dto.getTimeSpaces()) {
                int sub = Func.toInt(startDate.until(theDay, ChronoUnit.DAYS));
                int code1 = (sub * dto.getTimeSpaces().size()) % dto.getDailyShifts().size() + timeSpace.getCode();
                String dailyShift1 = shiftCode.get(code1);

                DailyShiftVO dsVo = new DailyShiftVO();
                dsVo.setWorkDate(theDay);
                dsVo.setTimeSpace(timeSpace.getTimeSpace());
                dsVo.setDailyShift(dailyShift1);

                res.add(dsVo);
            }
            theDay = theDay.plusDays(1);
        }

        for (DailyShiftVO vo : res) {
            vo.setDailyShiftName(DictBizCache.getValue("daily_shift", vo.getDailyShift()));
            vo.setTimeSpaceName(DictBizCache.getValue("time_space", vo.getTimeSpace()));
        }
        return res;
    }

    @Override
    public boolean generateNewShifts(GenerateShiftsDTO dto) {
        if (Func.isNull(dto.getRuleId())) {
            throw new RuntimeException("规则ID为空");
        }
        List<ShiftRuleTimeSpaceVO> timeSpaces = srTimeSpaceService.selectSRTimeSpaceListByRuleId(dto.getRuleId().toString());
        Map<Integer, String> dailyShiftsMap = srDailyShiftService.selectSRDailyShiftMapByRuleId(dto.getRuleId());

        List<DailyShift> newShiftList = new ArrayList<>();

        int loopTime = Func.isNull(dto.getDays()) || dto.getDays() == 0?Func.toInt(dto.getInitDate().until(dto.getEndDate(), ChronoUnit.DAYS)):dto.getDays();
        loopTime = Math.min(loopTime, 366);
        LocalDate theDay = dto.getInitDate();
        for (int i = 0; i <= loopTime; i++) {
            for (ShiftRuleTimeSpaceVO timeSpace : timeSpaces) {
                int sub = Func.toInt(dto.getInitDate().until(theDay, ChronoUnit.DAYS));
                int code1 = (sub * timeSpaces.size()) % dailyShiftsMap.size() + timeSpace.getCode();
                String dailyShift1 = dailyShiftsMap.get(code1);

                QueryWrapper<DailyShift> shiftQuery = new QueryWrapper<>();
                shiftQuery.lambda()
                        .eq(DailyShift::getWorkDate, theDay)
                        .eq(DailyShift::getTimeSpace,timeSpace.getTimeSpace())
                        .eq(DailyShift::getIsDeleted, 0).last("limit 1");
                DailyShift shift = new DailyShift();
                DailyShift exist = shiftService.getOne(shiftQuery);
                if (!Func.isNull(exist)) {
                    shift = exist;
                }
                shift.setWorkDate(theDay);
                shift.setTimeSpace(timeSpace.getTimeSpace());
                shift.setDailyShift(dailyShift1);
                shift.setRuleId(dto.getRuleId());

                newShiftList.add(shift);
            }
            theDay = theDay.plusDays(1);
        }
        return shiftService.saveOrUpdateBatch(newShiftList);
    }

    @Override
    public IPage<ShiftRuleVO> selectShiftRulePage(ShiftRuleSearchDTO dto, IPage<ShiftRuleVO> page) {
        List<ShiftRuleVO> data = baseMapper.selectShiftRuleList(dto, page);
        return page.setRecords(data);
    }

    @Override
    public List<ShiftRuleVO> selectShiftRuleList(ShiftRuleSearchDTO dto) {
        return baseMapper.selectShiftRuleList(dto, null);
    }

}